var app = app || {};
/*
Der Controller übernimmt die gesamte Steuerung der App.
Über die bereitgestellten Funktionen werden alle weiteren Elemente angesteuert.
*/
app.Controller = {
    /*
    ruft weitere inits auf und setzt die globale Variable ob sich die App im testmodus befindet
    */
    init: function(isTest) {
        app.isTest = isTest;
        app.Model.Data.init();
        try {
            app.Client.init();
        } catch (err) {
            app.View.Notifications.showMessageBanner('Keine Verbindung zum Server möglich. Es kann nur offline gearbeitet werden.')
        }
    },
    /*
    Die Funktion wird aufgerufen wenn im createView auf den Button Erstellen geklickt wurde.
    Es wird ein neues Turnier erzeugt und local gespeichert.
    Die Rechte des Administrators werden erteilt.
    Es wird auf die tabellen-Ansicht navigiert.
    Dem Server wird das erstellte Turnier gesendet.
    */
    newTournament: function(TournamentName, pwd, competitors) {
        app.Model.Data.setClientTournament(app.Model.TournamentLogic.createTournament(competitors, TournamentName));
        if (app.Model.Data.getClientTournament()) {
            var id = Math.random().toString(36).substring(3, 16) + +new Date;
            //TODO: geräte id hinzufügen in die Zufallszahl
            app.Model.Data.setIsAdmin(true);
            app.Model.Data.createTableData();
            app.router.navigate('table', {
                trigger: true
            });
            app.Client.newTournament(app.Model.Data.getClientTournament(), pwd);
        } else {
            app.View.Notifications.showMessageBox('Fehler beim Turnier anlegen.', 'Das Turnier konnte nicht angelegt werden. Bitte die Eingabe überprüfen.');
        }
    },
    /*
    Wenn das Turnier erfolgreich auf dem Server gespeichert wurde,
    wird eine Meldung an den Benutzer gegeben.
    */
    saveSuccess: function(id) {
        app.Model.Data.setTournamentID(id);
        app.View.Notifications.showMessageBanner("Turnier wurde auf dem Server gespeichert.");
    },
    /*
    Funktion wird aufgerufen, wenn ein Turnier verlassen wird.
    Die lokalen Turnier-Daten werden zurückgesetzt.
    Es Wird auf die Startseite navigiert.
    Dem Server wird mitgeteilt, dass der Client das Turnier verlassen hat.
    */
    leaveTournament: function() {
        app.Model.Data.resetClientTournament();
        app.router.navigate('home', {
            trigger: true
        });
        app.Client.leaveTournament();
    },
    /*
    Wenn auf Turnier beenden geklickt wurde, wird diese Funktion ausgeführt.
    Die lokalen Turnier-Daten werden zurückgesetzt.
    Es Wird auf die Startseite navigiert.
    Dem Server wird mitgeteilt, dass der Client das Turnier beendet hat.
    */
    quitTournament: function() {
        app.Model.Data.resetClientTournament();
        app.router.navigate('home', {
            trigger: true
        });
        app.Client.quitTournament();
    },
    /*
    Funktion wird aufgerufen, wenn dem Turnier der id: id beigetreten werden soll
    Das Turnier wird beim Server angefragt.
    */
    joinTournament: function(id) {
        //
        app.Client.joinTournament(id);
    },

    /*
    Funktion wird aufgerufen, wenn der Server Spieländerungen sendet.
    Die Änderungen werden lokal eingearbeitet.
    Die Turnieransichten werden neu gezeichnet.
    Der Benutzer erhält eine Nachricht darüber, dass Änderungen vorliegen.
    */
    refreshGames: function(changes) {
        var gameIndex = parseInt(changes[0].index);
        app.Model.Data.updateGames(changes);
        app.View.Tournament.render();
        app.View.Notifications.showMessageBanner("Ergebniss in Spiel " + (gameIndex + 1) + " wurde eingetragen.");
    },
    /*
    Funktion wird aufgerufen, wenn dem Turnier der id: id administriert werden soll
    Das Turnier wird beim Server angefragt.
    */
    adminExistingTournament: function(id, pwd) {
        //
        app.Client.adminExistingTournament(id, pwd);
    },

    /*
    Funktion wird aufgerufen um gesamte Turnierliste abzufragen.
    Turnierliste wird beim Server angefragt.
    Empfangene Liste wird lokal gespeichert.
    */
    updateCompleteTournamentList: function(list) {
        var list = app.Client.getTournamentList();
        if (list) {
            app.Model.Data.setTournamentList(list);
        } else {
            app.View.Notifications.showMessageBox('Fehler bei dem Laden der Turnierliste', 'Die Turnierliste konnte nicht geladen werden.');
        }
    },
    /*
    Funktion wird aufgerunfen, wenn der Server Anderungen der Turnierliste sendet.
    Änderungen werden eingearbeitet.
    Liste in der Startansicht wird neu gezeichnet.
    */
    recieveUpdateTournamentList: function(data) {
        app.Model.Data.updateTournamentList(data);
        app.View.Home.render();
    },

    /*
    Funktion wird aufgerufen wenn Server das angeforderte Turnier zum beitreten oder Administrieren gesendet hat.
    Empfangenes Turnier, Rechte und ID werden gespeichert.
    Es wird zur tabellen-Ansicht navigiert.
    */
    recieveTournament: function(tournament, id, isAdmin) {
        app.Model.Data.setIsAdmin(isAdmin);
        app.Model.Data.setClientTournament(tournament);
        app.Model.Data.setTournamentID(id);
        app.Model.Data.createTableData();
        var path = 'table';
        app.router.navigate(path, {
            trigger: true
        });
    },

    /*
    Funktion wird aufgerufen, wenn ein Ergebnis eingetragen wurde.
    Ergebnis wird eingetragen und die resultierenden Änderungen werden an den Server gesendet.
    Es Wird zur tabellen-Ansicht navigiert.
    */
    setScore: function(score1, score2, gameIndex) {
        var changes = app.Model.TournamentLogic.setScoreandGetChanges(gameIndex, score1, score2);
        if (changes) {
            app.Client.setScore(changes);
            app.Model.Data.createTableData();
            app.router.navigate('table', {
                trigger: true
            });
        } else {
            app.View.Notifications.showMessageBox('Fehler', 'Das Ergebnis konnte nicht gesetzt werden. Überprüfen Sie ihre Eingabe.');
        }
    },

    /*
    Funktion wird aufgerufen, wenn Server Mitteilung sendet, dass das turnier beendet wurde.
    Mitteilung wird über Mitteilungsbox an den Benutzer weitergegeben.
    */
    gameover: function() {
        //
        app.View.Notifications.showMessageBox('Das Turnier wurde beendet', 'Der Administrator hat das Turnier beendet. Sie Können sich das Turnier noch weiterhin ansehen. Wenn Sie Das Turnier verlassen, können Sie jedoch nicht erneut beitreten.');
    }
}


/*
Der View beinhaltet alle Funktionen und Objekte, die den hauptinhalt der Seite bearbeiten.
Unterteilt in die verschiedenen Ansichten
Außerdem auch alle Funktionen um dem benutzer Mitteilung zu geben.
*/
app.View = {
    /*
    Home enthält alle funktionen um den hauptinhalt der Startseite bereitzustellen
    */
    Home: {
        /*
        Initialisiert die Seite und wird beim betreten der Ansicht aufgerufen.
        Die Aktuelle Turnierliste wird abgefragt.
        der Wrapper erhält ein Attribut der aktuellen Seite.
        Nach ein verstecken des Wrappers wird die Seite gezcihnet und dann wieder gezeigt.
        */
        init: function() {
            app.Controller.updateCompleteTournamentList();
            //Inhalt austauschen und aktuelle Seite festlegen
            $('#wrapper').attr('data-currentSite', 'home');
            $('#wrapper').slideUp('slow', function() {
                app.View.Home.render();
            });
            $('#wrapper').slideDown('slow');
        },

        /*
        Vor dem Austuaschen des Wrapperinhalts wird geprüft, ob der Benutzer sich tatsächlich auf der Startseite befindet.
        Das Benötigte template wird aus dem HTML geholt.
        Das template wird mit der Turnierliste gefüttert und der darausentsehende HTML-Code wird als Inhalt des wrappers gesetzt.
        ActionListener zum Beitreten und Verwalten werden gesetzt.
        */
        render: function() {
            if ($('#wrapper').attr('data-currentSite') === 'home') {
                _.templateSettings.variable = 'rc';
                var template = _.template(
                    $('#template-homeView').html()
                );
                $('#wrapper').html(
                    template({
                        list: app.Model.Data.getTournamentList()
                    })
                );
                //Eventlistener des wrappers einbinden
                $('#joinView input').keydown(function(e) {
                    var keycode = e.which || e.keyCode;
                    if (keycode == 13) {
                        e.preventDefault();
                        app.View.Home.adminExistingTournament();
                    }
                });
                $('#joinView form').submit(app.View.Home.joinTournament);
                $('#joinTournament').click(app.View.Home.joinTournament);
                $('#adminExistingTournament').click(app.View.Home.adminExistingTournament);
            }
        },

        /*
        Funktion wird ausgeführt wenn Auf den Button beitreten gedrückt wird.
        Wenn ein Turnier gewählt wurde wird die Funktion des Controllers aufgerufen, der das Event weiter behandelt.
        */
        joinTournament: function() {
            if ($("#select_tournamentList").val() != -1) {
                app.Controller.joinTournament($("#select_tournamentList").val());
            } else {
                app.View.Notifications.showMessageBox('Turnier auswählen', 'Bitte wählen Sie ein Turnier aus der Liste aus, das Sie verfolgen möchten.');
            }
        },
        /*
        Funktion wird ausgeführt wenn Auf den Button erstellen gedrückt wird.
        Wenn ein Turnier gewählt wurde wird die Funktion des Controllers aufgerufen, der das Event weiter behandelt.
        */
        adminExistingTournament: function() {
            if ($("#select_tournamentList").val() != -1) {
                app.Controller.adminExistingTournament($('#select_tournamentList').val(), $('#password_admin_existing').val());
            } else {
                app.View.Notifications.showMessageBox('Turnier auswählen', 'Bitte wählen Sie ein Turnier aus der Liste aus, das Sie administrieren möchten.');
            }
        }
    },
    /*
    Create enthält alle Funktionen um den Hauptinhalt der Erstellen-Ansicht bereitzustellen
    */
    Create: {
        /*
        Initialisiert die Seite und wird beim betreten der Ansicht aufgerufen.
        der Wrapper erhält ein Attribut der aktuellen Seite.
        Wrapper wird versteckt.
        Über das template wird die Ansicht erstellt
        Die EventListener werden gesetzt.
        Wenn sich die App im testmodus befindet werden die Felder vorbelegt.
        */
        init: function() {
            //Wrapper austauschen
            $('#wrapper').attr('data-currentSite', 'create');
            var template = _.template(
                $('#template-createView').html()
            );
            $('#wrapper').slideUp('slow', function() {
                $('#wrapper').html(
                    template()
                );
                //Inputfelder für test befüllen
                if (app.isTest) {
                    $('#competitorsList input').each(function(index, el) {
                        var tmpText = "Teilnehmer " + (index + 1);
                        $(el).val(tmpText);
                    });
                    $('#form_createTournament input[name="tf_tournamentName"]').val("Test-Turnier");
                    $('#form_createTournament input[name="tf_password"]').val("pwd");
                }

                //Eventlistener im wrapper
                $('#form_createTournament').submit(app.View.Create.submit_createTournament);
                $('#competitorsList input').last().keydown(app.View.Create.inputKeyEvent);
                $('#btn_addCompetitor').click(app.View.Create.addCompetitorInput);
                $('#wrapper').slideDown('slow');
            });
        },
        /*
        Funktion reagiert auf Keyevents im letzten Inputfeld
        wird Tab gedrückt wird ein Teilnehmer hinzugefügt.
        Wird DELETE gedrücket soll das Letzte Feld wenn leer gelöscht werden
        */
        inputKeyEvent: function(e) {
            if (e.keyCode == 9) {
                app.View.Create.addCompetitorInput();
            } else if (e.keyCode == 8) {
                return app.View.Create.removeCompetitorInput();
            }
        },
        /*
        Ein Inputfeld wird für einen weiteren Spieler hinzugefügt
        Vom bisherigen letzten Inputfeld werden die Listener entfernt.
        Es wird ein Label und ein Inputfeld hinzugefügt, welches dann die Listener erhält.
        */
        addCompetitorInput: function() {

            $('#competitorsList input:last-child').unbind('keydown');
            var index = $('#competitorsList input').length + 1;
            //ggf auch als template
            $('#competitorsList').append($('<label></label>')
                .html('Teilnehmer ' + index)
            );
            $('#competitorsList').append($('<input/>')
                .attr('type', 'text')
                .attr('placeholder', 'Name')
                .keydown(app.View.Create.inputKeyEvent)
            );
        },
        /*
        Wenn Noch mindestens ein Inputfeld für einen teilnehmer vorhanden ist und das letzte Inputfeld leer ist,
        wird das letzte Feld und label gelöscht.
        Der Fokus und Die Listener werden auf das nun letzte gesetzt.
        */
        removeCompetitorInput: function() {
            if ($('#competitorsList input').length > 1 && $('#competitorsList input').last().val() == "") {

                $('#competitorsList input').last().remove();
                $('#competitorsList label').last().remove();
                $('#competitorsList input').last().keydown(app.View.Create.inputKeyEvent)
                    .focus();
                return false;
            }
        },
        /*
        Wird die Eingabe der turnierdaten bestätigt.
        werden die Felder ausgelesen. Die Teilnehmer werden in ein String array geschrieben.
        die Werte werden an die Funktion des Controllers übergeben.
        */
        submit_createTournament: function() {
            var competitorArray = [],
                inputPwd = $('#form_createTournament input[name="tf_password"]').val(),
                inputName = $('#form_createTournament input[name="tf_tournamentName"]').val();
            $('#competitorsList input').each(function() {
                if ($(this).val() != "") {
                    competitorArray.push($(this).val());
                    $(this).val('');
                }
            });
            app.Controller.newTournament(inputName, inputPwd, competitorArray);
            return false;
        }
    },
    /*
    Tournament stellt Funktionen bereit, die alle Turnieransichten und deren hauptinhalte betreffen.
    */
    Tournament: {
        /*
        Teilt die neuzeichenen Funktionen der aktuellen Ansicht zu.
        */
        render: function() {
            if ($('#wrapper').attr('data-currentSite') == 'table') {
                app.View.Table.render();
            } else if ($('#wrapper').attr('data-currentSite') == 'tree') {
                app.View.Tree.render();
            } else if ($('#wrapper').attr('data-currentSite') == 'ranking') {
                app.View.Ranking.render();
            }
        }
    },
    /*
    Table enthält alle Funktionen um den Hauptinhalt der Tabellen-Ansicht bereitzustellen
    */
    Table: {
        /*
        Initialisiert die Seite und wird beim betreten der Ansicht aufgerufen.
        der Wrapper erhält ein Attribut der aktuellen Seite.
        Wrapper wird versteckt.
        RenderFunktion wird aufgerufen.
        Wrapper wird wieder gezeigt.
        */
        init: function() {
            $('#wrapper').attr('data-currentSite', 'table');
            //Wrapper austauschen
            $('#wrapper').slideUp('slow', function() {
                app.View.Table.render();
            });
            $('#wrapper').slideDown('slow');
        },
        /*
        Vor dem Austuaschen des Wrapperinhalts wird geprüft, ob der Benutzer sich tatsächlich in der tabellenansicht befindet.
        Die TurnierDaten werden aufbereitet, um sie in die benötigte Form für das template zu bringen.
        Das Benötigte template wird aus dem HTML geholt.
        Das template wird mit den aufbereiteten Daten gefüttert und der darausentsehende HTML-Code wird als Inhalt des wrappers gesetzt.
        ActionListener zum Bearbeiten werden gesetzt wenn die rechte vorhanden sind.
        */
        render: function() {
            if ($('#wrapper').attr('data-currentSite') == 'table') {
                if (app.Model.Data.getClientTournament() != null && app.Model.Data.getClientTournament() !== "") {
                    if (!app.Model.Data.tableData) {
                        app.Model.Data.createTableData();
                    }
                    _.templateSettings.variable = 'rc';

                    var template = _.template(
                        $('#template-tableView').html()
                    );
                    $('#wrapper').html(
                        template({
                            rounds: app.Model.Data.tableData
                        })
                    );
                    if (app.Model.Data.getIsAdmin()) {
                        $('#tableView tr').hover(function() {
                                $(this).addClass('tr-hover')
                                    .css('cursor', 'pointer');
                            }, function() {
                                $(this).removeClass('tr-hover')
                                    .css('cursor', 'pointer');
                            })
                            .click(function() {
                                var path = 'edit/' + this.getAttribute('number');
                                app.router.navigate(path, {
                                    trigger: true
                                });
                            });
                    }
                } else {
                    app.View.Notifications.showMessageBox('Fehler beim Laden des Turniers', 'Das Turnier konnte nicht geladen werden.');
                }
            }

        }
    },
    /*
    Tree enthält alle Funktionen um den Hauptinhalt der Baum-Ansicht bereitzustellen
    */
    Tree: {
        /*
        Initialisiert die Seite und wird beim betreten der Ansicht aufgerufen.
        der Wrapper erhält ein Attribut der aktuellen Seite.
        RenderFunktion wird aufgerufen.
        */
        init: function() {
            $('#wrapper').attr('data-currentSite', 'tree');
            //Wrapper austauschen
            app.View.Tree.render();
        },

        /*
        Vor dem Austuaschen des Wrapperinhalts wird geprüft, ob der Benutzer sich tatsächlich in der Baum-Ansicht befindet.
        Die TurnierDaten werden aufbereitet, um sie in die benötigte Form für das BracketsFramework zu bringen.
        Die Daten werden an die Bracketfunktion übergeben um den Baum zu zeichnen.
        ActionListener zum Bearbeiten werden gesetzt wenn die rechte vorhanden sind.
        */
        render: function() {
            if ($('#wrapper').attr('data-currentSite') == 'tree') {
                var template = _.template(
                    $('#template-treeView').html()
                );
                $('#wrapper').html(
                    template()
                );
                try {
                    var erg = app.View.Tree.doubleEliminationData();
                    $("#treeView").bracket({
                        skipConsolationRound: true,
                        skipSecondaryFinal: true,
                        init: erg
                    });
                    var matches = $(".round").children();
                    for (var m = 0; m < matches.length; m++) {
                        matches[m].setAttribute("number", erg.matchIDs[m]);
                    }
                    if (app.Model.Data.getIsAdmin()) {
                        var matches = $(".round").children();
                        var m;
                        for (m = 1; m < matches.length; m++) {
                            matches[m].setAttribute("number", erg.matchIDs[m - 1]);
                        }
                        matches[0].setAttribute("number", erg.matchIDs[m - 1]);
                        $(".match").click(function() {
                            $(".match").unbind('click', doubleClickEvent);
                            $(this).click(doubleClickEvent);
                        });

                        var doubleClickEvent = function() {
                            var gameIndex = this.getAttribute('number') || -1,
                                path = 'edit/' + gameIndex; // + this.getAttribute('number');
                            app.router.navigate(path, {
                                trigger: true
                            });
                        }
                    }
                } catch (err) {
                    app.View.Notifications.showMessageBox('Fehler', 'Interner Fehler. Die Baumansicht kann nicht gezeichnet werden');
                }
            }
        },
        /*
        Bringt die TurnierDaten in die Form die JQuery-Bracket benötigt.
        */
        doubleEliminationData: function() {
            var t = app.Model.Data.getClientTournament();
            var c = app.Model.TournamentLogic;

            var teams = [];

            for (var i = 0; i < t.mainRound.length; i++) {
                var player = [];
                if (t.competitorsList[t.gameList[t.mainRound[i]].player1] == null) {
                    player.push("Freilos");
                } else {
                    player.push(t.competitorsList[t.gameList[t.mainRound[i]].player1].name);
                }
                if (t.competitorsList[t.gameList[t.mainRound[i]].player2] == null) {
                    player.push("Freilos");
                } else {
                    player.push(t.competitorsList[t.gameList[t.mainRound[i]].player2].name);
                }
                teams.push(player);
            }

            var matchIDs = [],
                results = [],
                resultsMR = [];
            
            var matchIDs = [];

            for (var i = 0; i < t.mainRound.length; i++) {
                var r = [];
                matchIDs.push(t.mainRound[i]);
                r.push(t.gameList[t.mainRound[i]].scorePlayer1);
                r.push(t.gameList[t.mainRound[i]].scorePlayer2);
                for (var j = 0; j < r.length; j++) {
                    if (r[j] == -1) {
                        r[j] = null;
                    }
                }
                resultsMR.push(r);
            }

            var resultsWB = [];
            resultsWB.push(resultsMR);
            for (var i = 1; i <= t.winnersbracketRoundNumber; i++) {
                var wbr = c.getWinnersbracketRound(i);
                matchIDs = matchIDs.concat(wbr);
                var round = [];
                for (var j = 0; j < wbr.length; j++) {
                    var r = [];
                    r.push(t.gameList[wbr[j]].scorePlayer1);
                    r.push(t.gameList[wbr[j]].scorePlayer2);
                    for (var k = 0; k < r.length; k++) {
                        if (r[k] == -1) {
                            r[k] = null;
                        }
                    }
                    round.push(r);
                }
                resultsWB.push(round);
            }
            results.push(resultsWB);

            var resultsLB = [];
            for (var i = 1; i <= t.losersbracketRoundNumber; i++) {
                var lbr = c.getLosersbracketRound(i);
                matchIDs = matchIDs.concat(lbr);
                var round = [];
                for (var j = 0; j < lbr.length; j++) {
                    var r = [];
                    r.push(t.gameList[lbr[j]].scorePlayer1);
                    r.push(t.gameList[lbr[j]].scorePlayer2);
                    for (var k = 0; k < r.length; k++) {
                        if (r[k] == -1) {
                            r[k] = null;
                        }
                    }
                    round.push(r);

                }
                resultsLB.push(round);
            }
            results.push(resultsLB);

            var final = t.gameList[t.gameList.length - 1];
            matchIDs.push(t.gameList.length - 1);
            var fscore = [];
            fscore.push(final.scorePlayer1);
            fscore.push(final.scorePlayer2);


            var resultsFI = [];
            var fakeScr = [null, null];
            var fakeFnl = [];
            fakeFnl.push(fakeScr);
            fakeFnl.push(fakeScr);
            resultsFI.push(fakeFnl);
            fakeFnl = [];
            fakeFnl.push(fscore);
            resultsFI.push(fakeFnl);

            results.push(resultsFI);

            var erg = {
                teams: teams,
                results: results,
                matchIDs : matchIDs
            }

            return erg;
        },
        /*
        Setzt die ActionListener zum bearbeiten, falls die rechete erhalten werden.
        */
        recievedAdminPermissions: function() {
            $(".match").click(function() {
                var path = 'edit/-1'; // + this.getAttribute('number');
                app.router.navigate(path, {
                    trigger: true
                });
            });
        }

    },
    /*
    Ranking enthält alle Funktionen um den Hauptinhalt der Rangfolgen-Ansicht bereitzustellen
    */
    Ranking: {
        /*
        Initialisiert die Seite und wird beim betreten der Ansicht aufgerufen.
        der Wrapper erhält ein Attribut der aktuellen Seite.
        Wrapper wird versteckt.
        RenderFunktion wird aufgerufen.
        Wrapper wird wieder gezeigt.
        */
        init: function() {
            $('#wrapper').attr('data-currentSite', 'ranking');
            //Wrapper austauschen
            $('#wrapper').slideUp('slow', function() {
                app.View.Ranking.render();
            });
            $('#wrapper').slideDown('slow');
        },
        /*
        Vor dem Austuaschen des Wrapperinhalts wird geprüft, ob der Benutzer sich tatsächlich in der Rangfolgen-Ansicht befindet.
        Die TurnierDaten werden aufbereitet, um sie in die benötigte Form für das template zu bringen.
        Das Benötigte template wird aus dem HTML geholt.
        Das template wird mit den aufbereiteten Daten gefüttert und der darausentsehende HTML-Code wird als Inhalt des wrappers gesetzt.
        */
        render: function() {
            if ($('#wrapper').attr('data-currentSite') == 'ranking') {
                if (app.Model.Data.getClientTournament() != null && app.Model.Data.getClientTournament() !== "") {
                    _.templateSettings.variable = 'rc';
                    var template = _.template(
                        $('#template-rankingView').html()
                    );
                    $('#wrapper').html(
                        template({
                            list: app.View.Ranking.prepareData()
                        })
                    );
                } else {
                    app.View.Notifications.showMessageBox('Fehler beim Laden des Turniers', 'Das Turnier konnte nicht geladen werden.');
                }
            }

        },
        /*
        berechnet Aus den Turnierdaten die Rangfolge der Spieler und gibt die Rangfolge als Liste zurück.
        */
        prepareData: function(gameNo) {
            var cTournament = app.Model.Data.getClientTournament(),
                data = [],
                rang = cTournament.fieldSize,
                player,
                finalGame = cTournament.gameList[cTournament.final];;

            function getPlayer(game) {
                var player = false;
                if (game.player1 !== -1 && game.player2 !== -1) {
                    if (game.player1 != null && game.player1 !== "" && game.player2 != null && game.player2 !== "") {
                        if (game.scorePlayer1 == -1 && game.scorePlayer2 == -1) { //Spiel noch nicht gespielt
                            player = "wird gespielt";
                        } else {
                            player = cTournament.competitorsList[app.Model.TournamentLogic.getLoser(game)].name;
                        }
                    } else {
                        player = "N/A";
                    }
                }
                return player;
            }

            for (var i = 1; i <= cTournament.losersbracketRoundNumber; i++) {
                var loserRound = app.Model.TournamentLogic.getLosersbracketRound(i);
                rang = rang - (loserRound.length);
                for (var k = 0; k < loserRound.length; k++) {
                    player = getPlayer(cTournament.gameList[loserRound[k]]);
                    if (player) {
                        data.push({
                            ranking: rang + 1,
                            player: player
                        });
                    }
                }
            }
            player = getPlayer(finalGame);

            if (player) {
                data.push({
                    ranking: 2,
                    player: player
                });
                if (finalGame.player1 != null && finalGame.player1 !== "" && finalGame.player2 != null && finalGame.player2 !== "") {
                    if (finalGame.scorePlayer1 == -1 && finalGame.scorePlayer2 == -1) { //Spiel noch nicht gespielt
                        player = "wird gespielt";
                    } else {
                        player = cTournament.competitorsList[app.Model.TournamentLogic.getWinner(finalGame)].name;
                    }
                } else {
                    player = "N/A";
                }
                data.push({
                    ranking: 1,
                    player: player
                });
            }
            data.reverse();
            return data;
        }
    },
    /*
    Edit enthält alle Funktionen um den Hauptinhalt der Bearbeiten-Ansicht bereitzustellen
    */
    Edit: {
        //Speichert das ausgewählte Spiel aus der Dropdownliste
        selectedGame: -1,

        /*
        Initialisiert die Seite und wird beim betreten der Ansicht aufgerufen.
        der Wrapper erhält ein Attribut der aktuellen Seite.
        Wrapper wird versteckt.
        RenderFunktion wird aufgerufen.
        Wrapper wird wieder gezeigt.
        */
        init: function(gameIndex) {
            app.View.Edit.selectedGame = isNaN(gameIndex) ? -1 : gameIndex;
            //Wrapper austauschen
            $('#wrapper').attr('data-currentSite', 'edit');
            $('#wrapper').slideUp('slow', function() {
                app.View.Edit.render();
            });
            $('#wrapper').slideDown('slow');
        },
        /*
        Vor dem Austuaschen des Wrapperinhalts wird geprüft, ob der Benutzer sich tatsächlich in der Bearbeiten-Ansicht befindet.
        Die Spieldaten und turnierDaten werden aufbereitet, um sie in die benötigte Form für das template zu bringen.
        Das Benötigte template wird aus dem HTML geholt.
        Das template wird mit den aufbereiteten Daten gefüttert und der darausentsehende HTML-Code wird als Inhalt des wrappers gesetzt.
        */
        render: function() {
            if ($('#wrapper').attr('data-currentSite') === 'edit') {
                _.templateSettings.variable = 'rc';
                var template = _.template(
                    $('#template-editView').html()
                );
                $('#wrapper').html(
                    template(prepareData())
                );
                $('#gamesSelection').change(function(event) {
                    var path = 'edit/' + $(this).val();
                    app.router.navigate(path, {
                        trigger: true
                    });
                });
                $('#btn_setScore').click(app.View.Edit.submitEdit);
            }
            /*
            Bestimmt aus den Turnierdaten eine Liste aller Spiele sowie eine Aufbereitung des ausgewählten Spiels.
            */
            function prepareData() {
                var currentGame,
                    player1String,
                    player2String,
                    preparedData = {
                        gamenumber: app.View.Edit.selectedGame,
                        gamenumbers: []
                    };
                $.each(app.Model.Data.getClientTournament().gameList, function(index, val) {
                    preparedData.gamenumbers.push(index);
                });
                if (app.View.Edit.selectedGame > -1) {
                    currentGame = app.Model.Data.getClientTournament().gameList[app.View.Edit.selectedGame];
                    preparedData.editable = currentGame.editable;
                    if (currentGame.player1 !== null && currentGame.player1 !== "") {
                        if (currentGame.player1 === -1) {
                            player1String = "Freilos";
                        } else if (currentGame.player1 > -1) {
                            player1String = app.Model.Data.getClientTournament().competitorsList[currentGame.player1].name;
                        }
                    }
                    if (currentGame.player2 !== null || currentGame.player1 !== "") {
                        if (currentGame.player2 === -1) {
                            player2String = "Freilos";
                        } else if (currentGame.player2 > -1) {
                            player2String = app.Model.Data.getClientTournament().competitorsList[currentGame.player2].name;
                        }
                    }
                    preparedData.game = {
                        score1: currentGame.scorePlayer1,
                        score2: currentGame.scorePlayer2,
                        player1: player1String,
                        player2: player2String
                    };
                }
                return preparedData;
            }
        },
        /*
        Wird Ausgeführt wenn Button Ergebnis setzen gedrückt wurde.
        Nach Validierung der Werte werden sie an die Controller-Funktion zur weiterverarbeitung gegeben.
        */
        submitEdit: function() {
            var score1 = $('#scoreP1').val(),
                score2 = $('#scoreP2').val();
            if (score1 && score2 && (score1 !== score2)) {
                app.Controller.setScore(parseInt(score1), parseInt(score2), app.View.Edit.selectedGame);
            } else {
                app.View.Notifications.showMessageBox('Falsche Eingabe', 'Bitte tragen Sie nur positive ganze Zahlen ein. Es darf kein Unentschieden eingetragen werden.');
            }
        }
    },
    /*
    Notifications stellt Funktionen bereit um Meldeungen an den Benutzer zu geben
    */
    Notifications: {
        /*
        Öffnen Ein Popup über der eigentlichen Seite mit dem angegebenen Inhalt.
        */
        showMessageBox: function(title, message) {
            $('#messageModal h4').html(title)
            $('#messageModal .modal-body p').html(message);
            $('#messageModal').modal('show');
        },
        /*
        Blendet für 2 Sekunden einen banner mit dem angegebenen Inhalt ein.
        */
        showMessageBanner: function(message) {
            $('#notification p').html(message);
            $('#notification').slideDown('fast');
            setTimeout(function() {
                $('#notification').slideUp('fast');
            }, 2000);
        }
    }

};
/*
Wenn Der DOM geladen ist wird die app initialisiert.
*/
$(document).ready(function() {
        console.log("DOM ready");
        app.Controller.init(true);
        app.router = new app.Router();
        Backbone.history.start();
});
